iT邦幫忙

2021 iThome 鐵人賽

DAY 19
1
Arm Platforms

基於ARM-M0架構MCU之落摔檢測韌體開發系列 第 19

[DAY 19] _ARM-M0-內核外設SysTick-寫個精準的Delay

  • 分享至 

  • xImage
  •  

SysTick是內核系統的定時器,先來看看SysTick來源在哪,下圖stm32f030cc的時鐘樹
https://ithelp.ithome.com.tw/upload/images/20211002/20141979GbyNv30Dnq.png

SysTick的時鐘為HCLK的8分頻,systick = HCLK/8
先提一下標準庫的大概運作方式,標準庫有寫好自動判斷要用外部石因還是內部,外部不正常或沒接上的話會自動使用內部HSI,有掛外部的話石中的進行路線如下圖,
https://ithelp.ithome.com.tw/upload/images/20211002/20141979qBhoL8qNl0.png
可以看到紅色路徑是有掛8M時會跑的路徑,重點來了!! PREDIV和PLLMUL是除多少和乘上多少,要來看看system_stm32f0xx.c,這個是標準庫剛方寫好的,建議不要去動了,官方寫的算完整了。以下是系統時鐘配置的函示
static void SetSysClock(void)這函是底下的一部份:

/*PLL configuration */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL6);

應該有看到除1和乘6吧,這個看法也可以套運在其他MCU上,標準庫都差不多的。
再來要看看STM32F0xxx Cortex-M0 programming manual M0編程手冊,要看這是因為我們是用操作內核的暫存器
手冊網址:https://www.st.com/resource/en/programming_manual/pm0215-stm32f0xxx-cortexm0-programming-manual-stmicroelectronics.pdf
先來看看程式吧:

"bsp_SysTick.h"

#ifndef __SYSTICK_H
#define __SYSTICK_H

#include "stm32f0xx.h"

#define STK_CSR (*(volatile unsigned long*)0xE00E010)
#define STK_RVR (*(volatile unsigned long*)0xE00E014)
#define STK_CVR (*(volatile unsigned long*)0xE00E018)
	
void delay_ms(uint16_t nms);//16
void delay_us(uint16_t nus);//16
void SysTick_Init(uint8_t SYSCLK);//8
#endif /* __SYSTICK_H */

上面可以看到我有定義三個暫存器指標,這三個位置在第四章節
https://ithelp.ithome.com.tw/upload/images/20211002/20141979OchVSdxKSk.png
再來看看

"bsp_SysTick.c"

#include "bsp_SysTick.h"
static uint8_t	fac_us=0;
static uint16_t	fac_ms=0;
void SysTick_Init(uint8_t SYSCLK)
{
	SysTick->CTRL = 0xfffffffb;
	fac_us=SYSCLK/8;
	fac_ms=(uint16_t)fac_us*1000;

}
void delay_ms(uint16_t nms)
{
	uint32_t temp;
	SysTick->LOAD = (uint32_t)nms*fac_ms;
	SysTick->VAL =0x00; 	
	SysTick->CTRL =0x01;
	do
	{
	 temp = SysTick->CTRL;
	}
	while((temp&0x01)&&(!(temp&(1<<16))));
	SysTick->CTRL = 0x00;
	SysTick->VAL =0x00;
}
void delay_us(uint16_t nus)
{
	uint32_t temp;
	SysTick->LOAD = (uint32_t)nus*fac_us;
	SysTick->VAL =0x00; 	
	SysTick->CTRL =0x01;
	do
	{
	 temp = SysTick->CTRL;
	}
	while((temp&0x01)&&(!(temp&(1<<16))));
	SysTick->CTRL = 0x00;
	SysTick->VAL =0x00;
}

這些操作方法M0編程手冊裡的說明很清楚了,有興趣的就自己看看吧,絕對不會看不懂很好理解。
再來是看主程式要如何使用?

main.c

#include "bsp_SysTick.h"

int main(void)
{
 SysTick_Init(48);//初始化
 delay_ms(20);
}

初始化後就可以使用了,我打48是因為我有掛外部石因震盪8M除1在乘6倍頻就會變48M,才會輸入48,還是不知道為甚麼在往前看看,假如不外掛石因用內部的話這邊要改成8
這絕對會比用迴圈計數還準。


上一篇
[DAY 18] _UART傳輸
下一篇
[DAY 20] _前20天的結語(落摔判斷流程)
系列文
基於ARM-M0架構MCU之落摔檢測韌體開發35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言